#include "tcp_receiver.hh"

// Dummy implementation of a TCP receiver

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

#define RECV_DBG 1 
void TCPReceiver::segment_received(const TCPSegment &seg) {
	DUMMY_CODE(seg);
	
    #if RECV_DBG
    printf("\n#seg_recvt\n");
    #endif
    bool  has_syn_flag = false;   
    if (seg.header().syn) {
		_isn = seg.header().seqno;
        has_syn_flag = true;   
    }
    
    if (seg.header().fin) {
        has_fin_flag = true;
    }

    if (_isn.has_value()) {

        uint64_t index =  unwrap(seg.header().seqno, _isn.value(), stream_out().bytes_written());
        std::string  data = seg.payload().copy();
        index = has_syn_flag ? index : (index - 1);
        _reassembler.push_substring(data, index, stream_out().input_ended());
       
       if (has_fin_flag && (unassembled_bytes() == 0)) {
            stream_out().end_input();
       }

        #if RECV_DBG
        printf("#syn %d, fin %d, has_syn_flag %d, has_fin_flag %d\n isn %u, seqno %u, index  %lu, seg_data %lu, end? %d\n", \
               seg.header().syn, seg.header().fin, has_syn_flag, has_fin_flag, \
               _isn.value().raw_value(), seg.header().seqno.raw_value(), \
               index, data.length(), stream_out().input_ended());
        printf("#buf w %lu, unassemble bytes %lu\n", stream_out().bytes_written(), unassembled_bytes());
        #endif
        
        if (seg.header().syn && seg.header().fin && (data.length() == 0)) {
                _next_seq = _next_seq + 2;
        } else if (seg.header().syn && has_fin_flag && (data.length() == 0)) { // why ???
                // fin first and then syn recv ?
                _next_seq = _next_seq + 1;
        } else {
            _next_seq = stream_out().bytes_written() + 1;
            if (stream_out().input_ended()) {
                 _next_seq = _next_seq + 1;
            }
        }
    }
}

optional<WrappingInt32> TCPReceiver::ackno() const { 
	if (_isn.has_value()) {
        return wrap(_next_seq, _isn.value());
    } else {
	    return {}; 
    }
}

size_t TCPReceiver::window_size() const { 
    return  _reassembler.stream_out().remaining_capacity();
}
